// The statistics on the resources used during the
// execution of the program. Here only the time
// is considered. It's adapted by Tudor's program.
// 4 Jun 2004

#include "resourcesUsageCounter.h"

void ResourcesUsageCounter::add(
    const timeval& t1,
    const timeval& t2,
    timeval& result)
{
    result.tv_usec = (t1.tv_usec + t2.tv_usec);
    result.tv_sec = (t1.tv_sec + t2.tv_sec);

    if (result.tv_usec >= 1000000)
    {
        result.tv_usec -= 1000000;
        result.tv_sec++;
    }
}

void ResourcesUsageCounter::substract(
    const timeval& final,
    const timeval& initial,
    timeval& result)
{
    result.tv_sec = final.tv_sec - initial.tv_sec;
    if (final.tv_usec >= initial.tv_usec)
        result.tv_usec = final.tv_usec - initial.tv_usec;
    else
    {
        result.tv_usec = 1000000 - (initial.tv_usec - final.tv_usec);
        result.tv_sec--;
    }
}

timeval ResourcesUsageCounter::userTimeInc()
{
    timeval result;


    substract(m_finalResourceUsage.ru_utime,
              m_initialResourceUsage.ru_utime, result);

    return result;
}

timeval ResourcesUsageCounter::systemTimeInc()
{
    timeval result;

    substract(m_finalResourceUsage.ru_stime,
              m_initialResourceUsage.ru_stime, result);

    return result;
}


timeval ResourcesUsageCounter::totalTimeInc()
{
    timeval result;

    add(userTimeInc(), systemTimeInc(), result);

    return result;
}

void ResourcesUsageCounter::start()
{
    // When the counter is in start mode, do nothing
    if (!counterStop) { 
      cout << "\n A star() is issued when the counter is counting. It plays no role.\n";
      return;
    }
    gettimeofday(&m_initialTimeStamp, 0);
    getrusage(RUSAGE_SELF, &m_initialResourceUsage);

    counterStop = false;

    // bug: the following two lines could be a reason to
    // destroy the content of some other variables (e.g., 
    // valueOfVars of BT class)
    // m_finalTimeStamp = m_initialTimeStamp;
    // m_finalResourceUsage = m_initialResourceUsage;
}


void ResourcesUsageCounter::stop()
{
    // When the counter is in stop mode, do nothing
    if (counterStop) { 
      cout << "\n A stop() is issued when the counter is idle. It plays no role.\n";
      return;
    }
    gettimeofday(&m_finalTimeStamp, 0);
    getrusage(RUSAGE_SELF, &m_finalResourceUsage);
    
    counterStop = true; 
    
    add(userT, userTimeInc(), userT);
    add(systemT,systemTimeInc(), systemT);
    add(totalT, totalTimeInc(), totalT); 
}

ostream& 
ResourcesUsageCounter::printTime(ostream& os, const timeval& tv) const
{
    int milliseconds = tv.tv_usec / 1000;
    int seconds = tv.tv_sec;
    int minutes = seconds / 60;
    int hours = minutes / 60;
    int days = hours / 24;
 
    if (days)
        os << days << "d";
 
    if (hours)
      // os << setw(2) << setfill(L'0') << hours % 24 << L"h";
      os << hours % 24 << "h";
 
    if (minutes)
      // os << setw(2) << setfill(L'0') << minutes % 60 << L"m";
      os << minutes % 60 << "m";
 
    // return os << setw(2) << setfill(L'0') << seconds % 60 << L"."
    //           << setw(3) << setfill(L'0') << milliseconds << L"s";
    os << seconds % 60 << "." << milliseconds << "s";

    return os; 
}
 
// print the current 'measure' of the counter
ostream& ResourcesUsageCounter::print(ostream& os) const
{
    // These fields are commented out because even though we might be
    // interested in looking at them, Linux (2.4.20 at least) fails to
    // report them.

    //wos << L"Max resident memory (Kb): " << m_rusage.ru_maxrss << endl;
    //wos << L"Text memory (Kb): " << textUsed() << endl;
    //wos << L"Data memory (Kb): " << dataUsed() << endl;
    //wos << L"Stack memory (Kb): " << stackUsed() << endl;

    //wos << L"Voluntary context switches: "
    //    << voluntaryContextSwitches() << endl;
    //wos << L"Involuntary context switches: "
    //    << involuntaryContextSwitches() << endl;

     /*os << "User/System/Total/Real time: ";
     ResourcesUsageCounter::printTime(os, userT);
	 os << "/";
     ResourcesUsageCounter::printTime(os, systemT);
	 os << "/";
     ResourcesUsageCounter::printTime(os, totalT);
	 os << "/";
	 */
    

    // if(counterStop == false) 

    // ResourcesUsageCounter::stop();
  
    ResourcesUsageCounter::printTime(os, totalT);

    return os;
}

